package io.github.jsp.service;

import io.github.jsp.cluster.ClusterManager;
import io.github.jsp.model.JobInfo;
import io.github.jsp.scheduler.TimeWheelScheduler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

@Service
public class DistributedScheduleService {
    
    private static final Logger logger = LoggerFactory.getLogger(DistributedScheduleService.class);
    
    @Autowired
    private JobInfoService jobInfoService;
    
    @Autowired
    private TimeWheelScheduler timeWheelScheduler;
    
    @Autowired
    private ClusterManager clusterManager;
    
    private ScheduledExecutorService scheduler;
    private final ConcurrentHashMap<Integer, JobInfo> scheduledJobs = new ConcurrentHashMap<>();
    
    @PostConstruct
    public void start() {
        scheduler = Executors.newScheduledThreadPool(2, r -> {
            Thread t = new Thread(r, "DistributedScheduleService");
            t.setDaemon(true);
            return t;
        });
        
        scheduler.scheduleAtFixedRate(this::scanAndScheduleJobs, 
            10, 30, TimeUnit.SECONDS);
        
        scheduler.scheduleAtFixedRate(this::cleanupStoppedJobs, 
            60, 60, TimeUnit.SECONDS);
        
        logger.info("DistributedScheduleService started");
    }
    
    @PreDestroy
    public void stop() {
        try {
            if (scheduler != null) {
                scheduler.shutdown();
                if (!scheduler.awaitTermination(5, TimeUnit.SECONDS)) {
                    scheduler.shutdownNow();
                }
            }
            logger.info("DistributedScheduleService stopped");
        } catch (Exception e) {
            logger.error("Error stopping DistributedScheduleService", e);
        }
    }
    
    private void scanAndScheduleJobs() {
        try {
            if (!clusterManager.isCurrentNodeActive()) {
                logger.warn("Current node is not active, skipping job scheduling");
                return;
            }
            
            List<JobInfo> jobs = jobInfoService.getSchedulableJobs();
            
            for (JobInfo job : jobs) {
                if (!isJobScheduled(job)) {
                    scheduleJob(job);
                }
            }
            
        } catch (Exception e) {
            logger.error("Error scanning and scheduling jobs", e);
        }
    }
    
    private void cleanupStoppedJobs() {
        try {
            scheduledJobs.entrySet().removeIf(entry -> {
                JobInfo currentJob = jobInfoService.getById(entry.getKey());
                if (currentJob == null || 
                    currentJob.getJobStatus() != 1 || 
                    currentJob.getTriggerStatus() != 1) {
                    
                    timeWheelScheduler.unscheduleJob(entry.getKey());
                    logger.debug("Unscheduled stopped job: {}", entry.getKey());
                    return true;
                }
                return false;
            });
            
        } catch (Exception e) {
            logger.error("Error cleaning up stopped jobs", e);
        }
    }
    
    private boolean isJobScheduled(JobInfo job) {
        JobInfo scheduledJob = scheduledJobs.get(job.getId());
        if (scheduledJob == null) {
            return false;
        }
        
        return scheduledJob.getJobCron().equals(job.getJobCron()) && 
               scheduledJob.getTriggerStatus().equals(job.getTriggerStatus()) &&
               timeWheelScheduler.isJobScheduled(job.getId());
    }
    
    public void scheduleJob(JobInfo job) {
        try {
            timeWheelScheduler.scheduleJob(job);
            scheduledJobs.put(job.getId(), job);
            logger.debug("Scheduled job: {}", job.getId());
        } catch (Exception e) {
            logger.error("Error scheduling job: {}", job.getId(), e);
        }
    }
    
    public void unscheduleJob(Integer jobId) {
        try {
            timeWheelScheduler.unscheduleJob(jobId);
            scheduledJobs.remove(jobId);
            logger.debug("Unscheduled job: {}", jobId);
        } catch (Exception e) {
            logger.error("Error unscheduling job: {}", jobId, e);
        }
    }
    
    public void rescheduleJob(JobInfo job) {
        unscheduleJob(job.getId());
        scheduleJob(job);
    }
    
    public boolean startJob(Integer jobId) {
        try {
            jobInfoService.updateTriggerStatus(jobId, 1);
            JobInfo job = jobInfoService.getById(jobId);
            if (job != null) {
                scheduleJob(job);
                return true;
            }
        } catch (Exception e) {
            logger.error("Error starting job: {}", jobId, e);
        }
        return false;
    }
    
    public boolean stopJob(Integer jobId) {
        try {
            jobInfoService.updateTriggerStatus(jobId, 0);
            unscheduleJob(jobId);
            return true;
        } catch (Exception e) {
            logger.error("Error stopping job: {}", jobId, e);
        }
        return false;
    }
}